#!/usr/bin/env python3
"""
使用 evdev 实现 Logitech 游戏手柄输入检测(sudo apt install python3-evdev)
支持动态检测手柄的断开与重连(evdev库比pygame更底层支持断开重连检测)
"""

import evdev
from evdev import InputDevice, categorize, ecodes
import select
import time
import threading
from collections import defaultdict

class LogitechGamepad:
    def __init__(self):
        self.device = None
        self.device_path = None
        self.axes = defaultdict(int)
        self.buttons = defaultdict(int)
        self.hats = defaultdict(tuple)
        
    def find_gamepad(self):
        """查找 Logitech F710 游戏手柄"""
        devices = [InputDevice(fn) for fn in evdev.list_devices()]
        for device in devices:
            # 查找 Logitech F710 手柄
            if "Logitech" in device.name and ("Gamepad" in device.name or "F710" in device.name):
                return device
        return None
    
    def connect(self):
        """连接到游戏手柄"""
        try:
            device = self.find_gamepad()
            if device:
                self.device = device
                self.device_path = device.path
                print(f"🎮 手柄已连接: {device.name}")
                print(f"设备路径: {device.path}")
                print("开始监听事件... 按 Ctrl+C 退出。\n")
                return True
            return False
        except Exception as e:
            print(f"连接手柄时出错: {e}")
            return False
    
    def is_connected(self):
        """检查手柄是否仍然连接"""
        if not self.device:
            return False
            
        try:
            # 检查设备是否仍然在系统设备列表中
            devices = [InputDevice(fn) for fn in evdev.list_devices()]
            return any(d.path == self.device_path for d in devices)
        except:
            return False
    
    def disconnect(self):
        """断开手柄连接"""
        if self.device:
            try:
                self.device.close()
            except:
                pass
            self.device = None
            self.device_path = None
    
    def read_events(self):
        """读取并处理手柄事件"""
        try:
            # 使用 select 实现非阻塞读取，超时时间为1秒
            r, _, _ = select.select([self.device], [], [], 1)
            if r:
                for event in self.device.read():
                    self.process_event(event)
                return True
            else:
                # 超时，但设备可能仍然连接
                return self.is_connected()
        except (OSError, IOError):
            # 设备已断开
            return False
    
    def process_event(self, event):
        """处理单个事件"""
        if event.type == ecodes.EV_KEY:
            # 按键事件
            key_name = self.get_button_name(event.code)
            self.buttons[event.code] = event.value
            action = "按下" if event.value == 1 else "释放"
            print(f"[KEY]  {key_name} {action}")
            
        elif event.type == ecodes.EV_ABS:
            # 绝对轴事件（摇杆、触发器、方向键）
            axis_name = self.get_axis_name(event.code)
            self.axes[event.code] = event.value
            print(f"[AXIS] {axis_name} = {event.value}")
    
    def get_button_name(self, code):
        """获取按钮名称"""
        button_names = {
            304: "A Button",
            305: "B Button", 
            307: "X Button",
            308: "Y Button",
            310: "LB",
            311: "RB",
            315: "Start",
            314: "Back",
            317: "LS",
            318: "RS"
        }
        return button_names.get(code, f"Button {code}")
    
    def get_axis_name(self, code):
        """获取轴名称"""
        axis_names = {
            0: "Left Stick X",
            1: "Left Stick Y",
            2: "LT Trigger",
            3: "Right Stick X",
            4: "Right Stick Y",
            5: "RT Trigger",
            16: "D-Pad X",
            17: "D-Pad Y"
        }
        return axis_names.get(code, f"Axis {code}")
    
    def display_current_state(self):
        """显示当前状态（用于调试）"""
        print("\033[H\033[J")  # 清屏
        print("当前手柄状态:")
        print("=" * 50)
        
        # 显示轴状态
        print("轴状态:")
        for code, value in self.axes.items():
            axis_name = self.get_axis_name(code)
            print(f"  {axis_name:15}: {value}")
        
        # 显示按钮状态
        print("\n按钮状态 (按下状态):")
        pressed_buttons = [code for code, value in self.buttons.items() if value == 1]
        for code in pressed_buttons:
            button_name = self.get_button_name(code)
            print(f"  {button_name}")

def main():
    """主函数"""
    gamepad = LogitechGamepad()
    
    try:
        while True:
            # 检查手柄连接状态
            if not gamepad.is_connected():
                print("正在检测 Logitech 游戏手柄...")
                if gamepad.connect():
                    print("🎮 手柄已连接，开始监听事件... 按 Ctrl+C 退出。\n")
                else:
                    print("未检测到游戏手柄，5秒后重新检测...")
                    time.sleep(5)
                    continue
            
            # 读取事件
            if not gamepad.read_events():
                print("手柄连接已断开，尝试重新连接...")
                gamepad.disconnect()
                time.sleep(1)
                
    except KeyboardInterrupt:
        print("\n程序退出")
    except Exception as e:
        print(f"程序出错: {e}")
    finally:
        gamepad.disconnect()

if __name__ == "__main__":
    main()